﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using BrainTechLLC;
using BrainTechLLC.WPF;
using ImageAppDataModels;
using ImageAppViewModels;
using WpfImageDuplicates;

namespace CompareMultiple.Plugin
{
    public partial class CompareMultipleImagesView : UserControl
    {
        public event EventHandler<ObjectEventArgsNonRef<FileImageViewModel, bool>> RequestDelete;        
        public event EventHandler<ObjectEventArgsNonRef<FileImageViewModel, bool>> RequestResizeDelete;
        public event EventHandler<ObjectEventArgsNonRef<FileImageViewModel, bool>> RequestResize;
        public event EventHandler<ObjectEventArgsNonRef<RotationParams, bool>> RequestRotate;

        public static readonly FindSimilarCommand FindSimilarCommand = new FindSimilarCommand();

        public static SolidColorBrush _brush = new SolidColorBrush(Colors.LightGreen);
        public static Thickness _standardThickness = new Thickness(1, 1, 1, 1);
        public static Thickness _bigThickness = new Thickness(3, 3, 3, 3);

        public event EventHandler<ObjectEventArgs<FileImageViewModel>> WantViewFull;

        public List<BasicImageInfoView> _basicInfo = new List<BasicImageInfoView>();
        public List<FileImageViewModel> _viewModels;
        public List<FileImageViewModel> _viewModelsList;
        public bool _similarityComplete;
        public WrapPanel _wrap;
        public List<FileImageViewModel> _lastSimilarList;

        public static readonly DependencyProperty FileImageViewModelsProperty =
            DependencyProperty.Register("FileImageViewModels", typeof(ObservableCollection<FileImageViewModel>), typeof(CompareMultipleImagesView), new PropertyMetadata(null, OnFileImageViewModel1PropertyChanged));

        public ObservableCollection<FileImageViewModel> FileImageViewModels
        {
            get { return (ObservableCollection<FileImageViewModel>)GetValue(FileImageViewModelsProperty); }
            set { SetValue(FileImageViewModelsProperty, value); }
        }

        private static void OnFileImageViewModel1PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CompareMultipleImagesView source = d as CompareMultipleImagesView;
            source.UpdateFileImageViewModel1(e.NewValue as ObservableCollection<FileImageViewModel>, e.OldValue as ObservableCollection<FileImageViewModel>);
        }

        public static readonly DependencyProperty ImageWidthProperty =
            DependencyProperty.Register("ImageWidth", typeof(double), typeof(CompareMultipleImagesView), new PropertyMetadata(400D, OnImageWidthPropertyChanged));

        public double ImageWidth
        {
            get { return (double)GetValue(ImageWidthProperty); }
            set { SetValue(ImageWidthProperty, value); }
        }

        private static void OnImageWidthPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CompareMultipleImagesView source = d as CompareMultipleImagesView;
            source.UpdateImageWidth((double)e.NewValue);
        }

        private void UpdateImageWidth(double width)
        {
            if (_wrap != null)
            {
                _wrap.ItemWidth = width;
                if (Settings.Values != null)
                {
                    Settings.Values.CompareMultipleWidth = width;
                }
            }
        }

        public static readonly DependencyProperty ImageHeightProperty =
                   DependencyProperty.Register("ImageHeight", typeof(double), typeof(CompareMultipleImagesView), new PropertyMetadata(400D, OnImageHeightPropertyChanged));

        public double ImageHeight
        {
            get { return (double)GetValue(ImageHeightProperty); }
            set { SetValue(ImageHeightProperty, value); }
        }

        private static void OnImageHeightPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CompareMultipleImagesView source = d as CompareMultipleImagesView;
            source.UpdateImageHeight((double)e.NewValue);
        }

        private void UpdateImageHeight(double height)
        {
            if (_wrap != null)
            {
                _wrap.ItemHeight = height;
                if (Settings.Values != null)
                {
                    Settings.Values.CompareMultipleHeight = height;
                }
            }
        }

        public static readonly DependencyProperty GroupNameProperty =
            DependencyProperty.Register("GroupName", typeof(string), typeof(CompareMultipleImagesView), new PropertyMetadata(string.Empty, OnGroupNamePropertyChanged));

        public string GroupName
        {
            get { return (string)GetValue(GroupNameProperty); }
            set { SetValue(GroupNameProperty, value); }
        }

        private static void OnGroupNamePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CompareMultipleImagesView source = d as CompareMultipleImagesView;
            source.UpdateGroupName((string)e.NewValue);
        }

        private void UpdateGroupName(string s)
        {
            currentGroupName.Text = s;
        }

        public static readonly DependencyProperty ShowSimilarityGroupProperty =
            DependencyProperty.Register("ShowSimilarityGroup", typeof(bool), typeof(CompareMultipleImagesView), new PropertyMetadata(true, OnShowSimilarityGroupPropertyChanged));

        public bool ShowSimilarityGroup
        {
            get { return (bool)GetValue(ShowSimilarityGroupProperty); }
            set { SetValue(ShowSimilarityGroupProperty, value); }
        }

        private static void OnShowSimilarityGroupPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CompareMultipleImagesView source = d as CompareMultipleImagesView;
            source.UpdateShowSimilarityGroup((bool)e.NewValue);
        }

        public void UpdateShowSimilarityGroup(bool val)
        {
            ShowSimilarityGroup = val;

            for (int n = 0; n < _basicInfo.Count; n++)
            {
                _basicInfo[n].ShowSimilarityGroup = val;
            }
        }

        private void UpdateFileImageViewModel1(ObservableCollection<FileImageViewModel> viewModel, ObservableCollection<FileImageViewModel> old)
        {
            if (viewModel != old)
            {
                FileImageViewModels = viewModel;

                if (_lastSimilarList != null)
                {
                    _lastSimilarList.Clear();
                    _lastSimilarList = null;
                }

                if (_viewModelsList != null)
                {
                    _viewModelsList.Clear();
                    _viewModelsList = null;
                }

                if (_viewModels != null)
                {
                    _viewModels.Clear();
                    _viewModels = null;
                }

                if (viewModel != null)
                {
                    for (int n = 0; n < viewModel.Count; n++)
                    {
                        viewModel[n].SetCurrentWidthHeight(ImageWidth, ImageHeight);
                    }
                }
                else
                {
                    for (int n = 0; n < _basicInfo.Count; n++)
                    {
                        var info = _basicInfo[n];
                        info.CalcHandler.Abort();
                        info.FileImageViewModel = null;
                    }
                    _basicInfo.Clear();

                    _groupHandler.ClearGroups();
                }

                _viewModelsList = viewModel == null ? null : new List<FileImageViewModel>(viewModel);

                if (old != null)
                {
                    old.Clear();
                }

                this.DataContext = FileImageViewModels;

                if (viewModel != null)
                {
                    ThreadStart ts = new ThreadStart(BackgroundWorkerThread2);
                    Thread t = ts.CreateAndRunThread(true);
                    t.Name = "BackgroundWorkerThread2";
                    t.Priority = ThreadPriority.BelowNormal;
                }
            }
        }

        public CompareMultipleImagesView()
        {
            InitializeComponent();
            Loaded += new RoutedEventHandler(CompareMultipleImagesView_Loaded);
        }

        void CompareMultipleImagesView_Loaded(object sender, RoutedEventArgs e)
        {
            ImageWidth = Settings.Values.CompareMultipleWidth;
            ImageHeight = Settings.Values.CompareMultipleHeight;
        }

        private void imgMain1_Loaded(object sender, RoutedEventArgs e)
        {
            ImageControl img = sender as ImageControl;
            Border b = img.Parent as Border;
            b.Width = ImageWidth;
            b.Height = ImageHeight - 72;
        }


        private BasicImageInfoView FindInfoViewForViewModel(FileImageViewModel vm)
        {
            for (int n = 0; n < _basicInfo.Count; n++)
            {
                if (_basicInfo[n].FileImageViewModel.FileName == vm.FileName)
                    return _basicInfo[n];
            }

            return null;
        }

        private void basicInfo_Loaded(object sender, RoutedEventArgs e)
        {
            var info = sender as BasicImageInfoView;
            info.ShowSimilarityGroup = ShowSimilarityGroup;
            _basicInfo.Add(info);
        }

        public int Factorial(int n)
        {
            if (n < 2)
                return 1;

            int result = 0;

            for (int i = n; i >= 2; i--)
            {
                result += i;
            }

            return result;
        }

        public void BackgroundWorkerThread2()
        {
            for (int n = 0; n < _viewModelsList.Count; n++)
            {
                var vm = _viewModelsList[n];
                var fi = vm.FileImage as FileImage;
                byte[] bytes = fi.EnsureImageBytesLoaded();

                if (!vm.BitmapLoaded)
                {
                    Dispatcher.BeginInvoke(new OneParamDelegate((o) =>
                    {
                        try
                        {
                            var vmLocal = o as FileImageViewModel;
                            vmLocal.LoadBitmap();
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.ToString());
                        }
                    }),
                    DispatcherPriority.Background, // verified okay
                    vm);
                }
            }
        }

        public void SetFindSimilarSearching(int n, int nMax)
        {
            if (nMax > 0)
            {
                findSimilar.Content = string.Format("Searching {0}/{1}", n, nMax);
            }
            else
            {
                findSimilar.Content = "Searching...";
            }
        }

        public void SetFindSimilarDone()
        {
            findSimilar.Content = "Done / Re-Find";
        }

        private void wrap_Loaded(object sender, RoutedEventArgs e)
        {
            _wrap = sender as WrapPanel;
            _wrap.ItemWidth = ImageWidth;
            _wrap.ItemHeight = ImageHeight;
            txtWidth.Text = ImageWidth.ToString();
            txtHeight.Text = ImageHeight.ToString();
        }

        private void btnNewWidthHeight_Click(object sender, RoutedEventArgs e)
        {
            double width;
            double height;

            if (!double.TryParse(txtWidth.Text, out width) || !double.TryParse(txtHeight.Text, out height))
                return;

            ImageWidth = width;
            ImageHeight = height;
        }

        private void lstItems_Loaded(object sender, RoutedEventArgs e)
        {
            if (_wrap == null)
            {
                var items = lstItems.GetAllChildren<WrapPanel>(true);
                _wrap = items[0];
            }
        }

        private void lstItems_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var sel = lstItems.GetSelected<FileImageViewModel>();
            if (sel.Count > 0)
            {
                var item = sel[0];

                HighlightSimilar(item.SimilarityGroups);
            }
        }

        public List<FileImageViewModel> GetAllSimilar(List<string> groupNames)
        {
            List<FileImageViewModel> results = new List<FileImageViewModel>();

            if (FileImageViewModels != null)
            {
                for (int n = 0; n < FileImageViewModels.Count; n++)
                {
                    var vm = FileImageViewModels[n];

                    if (vm.HasAny(vm.SimilarityGroups, groupNames))
                    {
                        results.Add(vm);
                    }
                }
            }

            return results;
        }

        public void HighlightSimilar(List<string> groupNames)
        {
            _lastSimilarList = GetAllSimilar(groupNames);

            if (FileImageViewModels != null)
            {
                for (int n = 0; n < FileImageViewModels.Count; n++)
                {
                    var vm = FileImageViewModels[n];

                    if (ShowSimilarityGroup && vm.HasAny(vm.SimilarityGroups, groupNames))
                    {
                        //vm.HighlightBorderBrush = _brush;
                        //vm.HighlightBorderThickness = _bigThickness;
                    }
                    else
                    {
                        //vm.HighlightBorderBrush = null;
                        //vm.HighlightBorderThickness = _standardThickness;
                    }
                }
            }
        }

        private void imgMain1_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            Image img = sender as Image;
            var vm = img.Tag as FileImageViewModel;

            if (WantViewFull != null)
                WantViewFull(this, new ObjectEventArgs<FileImageViewModel>(vm));
        }

        private void FindSimilar(object sender, ExecutedRoutedEventArgs e)
        {
            _similarityComplete = false;
            SetFindSimilarSearching(0, 0);
            _viewModels = new List<FileImageViewModel>();
            _viewModels.AddRange(FileImageViewModels);

            for (int n = 0; n < _viewModels.Count; n++)
            {
                var vm = _viewModels[n];
                vm.SimilarityGroups.Clear();
                vm.RaiseSimilarityGroupsChanged();
            }

            ThreadStart ts = new ThreadStart(BackgroundWorkerThreadFindSimilarity);
            Thread t = ts.CreateAndRunThread(true);
            t.Name = "BackgroundWorkerThreadFindSimilarity";
            t.Priority = ThreadPriority.BelowNormal;
        }

        private void btnShowInNewWindow_Click(object sender, RoutedEventArgs e)
        {
            if (_lastSimilarList == null || _lastSimilarList.Count == 0)
                return;

            _lastSimilarList.Sort(new Comparison<FileImageViewModel>((vm1, vm2) => vm2.Blur.CompareTo(vm1.Blur)));

            ObservableCollection<FileImageViewModel> list = new ObservableCollection<FileImageViewModel>();
            for (int n = 0; n < _lastSimilarList.Count; n++)
            {
                list.Add(_lastSimilarList[n]);
            }

            Commands.WantCompareMultipleInNewWindow.Execute(list, btnShowInNewWindow);
        }

        private void btnNextGroup_Click(object sender, RoutedEventArgs e)
        {
            _groupHandler.OpenNext();
        }

        private void thumbCommand_RequestDelete(object sender, ObjectEventArgsNonRef<FileImageViewModel, bool> e)
        {
            RequestDelete.RaiseEvent(sender, e.obj1, e.obj2);
        }

        private void thumbCommand_RequestResize(object sender, ObjectEventArgsNonRef<FileImageViewModel, bool> e)
        {
            RequestResize.RaiseEvent(sender, e.obj1, e.obj2);
        }

        private void thumbCommand_RequestResizeDelete(object sender, ObjectEventArgsNonRef<FileImageViewModel, bool> e)
        {
            RequestResizeDelete.RaiseEvent(sender, e.obj1, e.obj2);
        }

        private void thumbCommand_RequestRotate(object sender, ObjectEventArgsNonRef<RotationParams, bool> e)
        {
            RequestRotate.RaiseEvent(sender, e.obj1, e.obj2);
        }
    }
}
